using System;
using System.Collections.Generic;
using System.Configuration;
using Needle.Core.Activation;
using Needle.Core.Injection;
using Needle.Utils;

namespace Needle.Core.Configuration
{
    /// <summary>
    /// Describes an object.
    /// </summary>
    public class ObjectElement : ConfigurationElement
    {
        #region private class CfgActivationInfo

        private class CfgActivationInfo : IActivationInfo
        {
            /// <summary>
            /// Initializes a new instance of the CfgActivationInfo class.
            /// </summary>
            public CfgActivationInfo(InstanceId id, 
                IInjectionSite constructor, 
                IList<IInjectionSite> properties, 
                IList<IInjectionSite> methods)
            {
                _Id = id;
                _Type = constructor.Method.DeclaringType;
                _Constructor = constructor;
                List<IInjectionSite> sites = new List<IInjectionSite>();
                sites.AddRange(properties);
                sites.AddRange(methods);
                sites.Sort();
                _Methods = sites;
            }
            #region IActivationInfo Members

            private InstanceId _Id;
            public InstanceId Id
            {
                get
                {
                    return _Id;
                }
            }

            private Type _Type;
            public Type Type
            {
                get { return _Type; }
            }
            
            private IInjectionSite _Constructor;
            public IInjectionSite Constructor
            {
                get
                {
                    return _Constructor;
                }
            }

            private IList<IInjectionSite> _Methods;
            public IList<IInjectionSite> Methods
            {
                get
                {
                    return _Methods;
                }
            }

            #endregion
        }

        #endregion

        /// <summary>
        /// Returns the activation info for this ObjectElement
        /// </summary>
        public IActivationInfo GetActivationInfo()
        {
            try
            {
                InstanceId id = this.InstanceId;
                Type injectedType = System.Type.GetType(this.Type);
                IInjectionSite ctor = InjectedConstructor.GetInjectionSite(injectedType);
                IList<IInjectionSite> properties = InjectedProperties.GetInjectionSites(injectedType);
                IList<IInjectionSite> methods = InjectedMethods.GetInjectionSites(injectedType);
                return new CfgActivationInfo(id, ctor, properties, methods);
            }
            catch (Exception ex)
            {
                Exceptions.ThrowConfigError("Invalid object configuration.", ex, this);
            }
            return null;// can never happen, but makes compiler happy.
        }

        /// <summary>
        /// The object DependencyId
        /// </summary>
        public InstanceId InstanceId
        {
            get { return InstanceId.Parse(Id); }
            set { Id = value.ToString(); }
        }
        /// <summary>
        /// The object DependencyId as a string.
        /// </summary>
        [ConfigurationProperty(Element.Id, IsRequired = true, IsKey = true)]
        public string Id
        {
            get { return (string)this[Element.Id]; }
            set { this[Element.Id] = value; }
        }

        /// <summary>
        /// The concrete type as a string.
        /// </summary>
        [ConfigurationProperty(Element.Type, IsRequired = false, IsKey = false)]
        public string Type
        {
            get { return (string)this[Element.Type]; }
            set
            {
                this[Element.Type] = value;
            }
        }

        /// <summary>
        /// Injected constructor
        /// </summary>
        [ConfigurationProperty(Element.Constructor, IsRequired = false)]
        public ConstructorElement InjectedConstructor
        {
            get { return (ConstructorElement)this[Element.Constructor]; }
        }
        /// <summary>
        /// injected properties
        /// </summary>
        [ConfigurationCollection(typeof(PropertyElement))]
        [ConfigurationProperty(Element.Properties, IsRequired = false)]
        public PropertyElementCollection InjectedProperties
        {
            get { return (PropertyElementCollection)this[Element.Properties]; }
        }
        /// <summary>
        /// injected methods
        /// </summary>
        [ConfigurationCollection(typeof(MethodElement))]
        [ConfigurationProperty(Element.Methods, IsRequired = false)]
        public MethodElementCollection InjectedMethods
        {
            get { return (MethodElementCollection)this[Element.Methods]; }
        }
    }

}
